/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @file
 * @brief Interface of class string and a few API for C-string.
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#pragma once

#ifndef AMCC_STRING_H
#define AMCC_STRING_H

#include <string.h>

#include "amcc_config.h"

AMCC_DECL_BEGIN

// -----------------------------------------------------------------------
/// @name API for C-string
/// @{

/**
 * @brief Get a built-in long-long spaced string.
 *
 * This string is used to print, log some spaces.
 *
 * @return A long string only contains space.
 */
extern const char * amcc_long_spacestring();

/**
 * @brief Converts a char to a C-string.
 * <p>
 * This function generates a string surrounded by a pair of
 * single quotation marks.
 * <p>
 * For non-printable character, for example, smaller than space(0x20),
 * or greater than DELETE(0x7F), the output string is an escaped sequence.
 * 
 * @param buff the output string buff, and its minimum capacity is 7
 * @param c    the char converted
 * @return Return the argument 'buff' and always ends with null character.
 */
extern char* char2Cstring(char* buff, char c);

/**
 * @brief Convert a char-literal to an integer value of the corresponding char.
 *
 * @param literal pointer to a char-literal surrounded by a pair of single quotes
 *
 * @return A non-negative integer value of the corresponding char.
 *  Or return -1 if the value is out-of-range of 'int'.
 */
extern int  charLiteral2Int(const char* literal);

/**
 * @brief Creates a duplicate of the string pointed to by source.
 * @note  Caller MUST free the returned string.
 *
 * @param source pointer to the null-terminated string to duplicate
 * @return A pointer to the newly allocated string, or
 *         a null pointer if an error occurred.
 */
extern char * cstring_duplicate(const char * source);

/**
 * @brief Creates a copy of sub-string of big string.
 *        Caller MUST free the returned string.
 * @param source pointer to the null-terminated big string
 * @param from   starting subscript  in big string
 * @param maxLen max number of copied characters,
 *     a non-positive number means "copy chars until end of source"
 * @return A pointer to the newly allocated string, or
 *         a null pointer if an error occurred.
 * @note  Caller MUST free the returned string.
 */
extern char * cstring_substr(const char * source, int from, int maxLen);

/**
 * @brief Creates a new non-empty C-string object.
 *
 * The new object MUST be destroyed through function cstring_destroy().
 *
 * The length of this string is the minimum value of maxLen
 * and the length of cString.
 *
 * @param cString  pointer to a C-string terminated with a null character
 * @param maxLen   maximum length copied
 * @return On success, return a pointer to the new string object.
 *         On failure, return null.
 *
 * @note If cString is null or an empty string, this function will
 *       return an object representing an empty string.
 */
extern char * cstring_new(const char * cString, int maxLen);

/**
 * @brief Destroy this C-string object created by cstring_new().
 *
 * The pointer is invalid after the string object is destroyed.
 *
 * @param pThis pointer to this string
 */
extern void   cstring_destroy(char * pThis);

/**
 * @brief Performs a case-insensitive comparison of strings.
 * @param s1  null-terminated strings
 * @param s2  null-terminated strings
 * @return If s1 < s2 then return a negative integer,
 * if s1 == s2 then return 0,
 * if s1 > s2 then return a positive integer.
 */
extern int cstring_cmp_icase(const char* s1, const char* s2);

#define cstring_length(cString)     ((NULL==cString) ? 0 : strlen(cString))
#define cstring_is_empty(cString)   (NULL == cString || '\0' == cString[0])
#define cstring_text(cString)       cString
#define cstring_cmp(a, b)           strcmp(a, b)
#define cstring_copy(dest, src)     strcpy(dest, src )

/// @}
// -----------------------------------------------------------------------


// -----------------------------------------------------------------------
/// @name API of class string
/// @{

struct t_string_impl;

/**
 * @brief Type for string object with a reference-counter.
 *
 * This class has the following features: <br>
 * - One text may be shared by multiple string objects. <br>
 * - The copy-on-write technology is applied when a string object is updated.
 * <p>
 *
 * This class is used to support sharing a same text
 * between multiple token, words, etc.
 * <p>
 *
 * The text always terminates with a null character.
 */
typedef struct t_string {
    struct t_string_impl * impl; //!< internal data
} t_string, * t_string_ptr;

/**
 * @brief Creates a new non-empty string object.
 *
 * The new object MUST be destroyed through function string_destroy().
 *
 * The length of this string is the minimum value of maxLen
 * and the length of cString.
 *
 * @param cString  pointer to a C-string terminated with a null character
 * @param maxLen   maximum length copied
 * @return On success, return a pointer to the new string object.
 *         On failure, return null.
 *
 * @note If cString is null or an empty string, this function will
 *       return an object representing an empty string.
 */
extern t_string * string_new(const char * cString, int maxLen);

/**
 * @brief Destroy this string object created by string_new().
 *
 * The pointer is invalid after the string object is destroyed.
 *
 * @param pThis pointer to this string
 */
extern void string_destroy(t_string * pThis);

/**
 * @brief Get the C-string of this string object.
 *
 * @param pThis pointer to this string
 * @return A pointer to constant C-string held by this object.
 */
const char * string_text(const t_string * pThis);

/**
 * @brief  Get the length of this string.
 */
extern int string_length(const t_string * pThis);

/**
 * @brief  Whether this string is null or empty.
 */
extern bool string_is_empty(const t_string * pThis);

/**
 * @brief Copy all contents of 'pSource' into this string.
 * 
 * @param pThis    pointer to target, this string
 * @param pSource  pointer to source string
 * @return the number of characters copied from source.
 * 
 * @note If pSource is empty or null , this string becomes an empty string.
 */
extern int string_copy(t_string* pThis, const t_string * pSource);

/**
 * @brief Make a clone of this string.
 * @param pThis pointer to this string
 * @return Returns a pointer to the cloned object.
 */
extern t_string * string_clone(t_string * pThis);

/**
 * @brief Copy a C-string into this string object.
 * 
 * @param pThis    pointer to this string
 * @param cString  pointer to a C-style string to be copied
 * @return the number of characters copied from source.
 * 
 * @note If cString is null or empty, this function will
 *       return an object representing an empty string.
 */
extern int string_copyc(t_string * pThis, const char * cString);

/**
 * @brief Copy up to n chars of C-string into this string object.
 * 
 * @param pThis    pointer to this string
 * @param cString  pointer to a C-style string to be copied
 * @param n        maximum number of characters to copy, a negative value means 0
 * @return the number of characters copied from source.
 * 
 * @note If cString is null or empty, this function will
 *       return an object representing an empty string.
 */
extern int string_ncopyc(t_string*pThis, const char* cString, int n);

/**
 * @brief Compare string objects according rules of 'strcmp()'.
 * 
 * An empty string is always less than a non-empty string.
 * 
 * @param pThis     pointer to this string
 * @param pAnother  pointer to another string
 * 
 * @return If '*pThis' < '*pAnother' then return a negative integer,
 * if '*pThis' == '*pAnother' then return 0,
 * if '*pThis' > '*pAnother' then return a positive integer.
 */
extern int string_compare(const t_string* pThis, const t_string* pAnother);

/**
 * @brief Compare strings according rules of 'strcmp()'.
 * 
 * An empty string is always less than a non-empty string.
 * 
 * @param pThis  pointer to this string
 * @param pAnother   pointer to another C-style string
 * 
 * @return return a negative integer if '*pThis' < '*pAnother' or pThis is null;
 *   return 0 if '*pThis' == '*pAnother' or both pointer is null;
 *   return a positive integer if '*pThis' > '*pAnother' or pAnother is null.
 */
extern int string_comparec(const t_string* pThis, const char* pAnother);

/// @}
// -----------------------------------------------------------------------


// -----------------------------------------------------------------------
/// @name API of file system
/// @{

/**
 * @brief Get an absolute path-name that is the current working
 *        directory of this process.
 *
 * If the argument buff is NULL,
 * caller MUST free the returned memory.
 *
 * @param buff     a target buffer which size is sz_buff
 * @param sz_buff  length of buffer
 *
 * @return On success, this function return a pointer to a string
 *    containing the pathname of the current working
 *    directory--the same value as buf.
 * @return On failure, these functions return NULL, and errno is
 *    set to indicate the error.
 */
extern char* path_get_workdir(char* buff, int sz_buff);

/**
 * @brief Creates a directory object and its parents if it not exists.
 *
 * The 'dir' is a string like "name", "p1/name" or "p1/.../name".
 * Char '\\' is equal to '/', aka '/' is equal to '\\'.
 *
 * @param dir   pointer to the directory for store output files
 */
extern void path_create_dir(const char* dir);

/**
 * @brief Get name part of a file.
 * @param filepath  pointer to the file path
 * @return Return file name without its directory.
 */
extern const char* path_basename(const char* filepath);

/**
 * @brief Get the directory of a file.
 * @param filepath  pointer to the file path
 * @param buffer    points to a buffer which stores the result
 * @param sz_buffer max size of buffer
 * @return Return the argument buffer.
 */
extern char* path_dirname(const char* filepath, char* buffer, int sz_buffer);

/**
 * @brief Deletes the file whose name is specified in filename.
 * @param filename pointer to the file name
 * @return If the file is successfully deleted,
 *        a zero value is returned.
 *  On failure, a nonzero value is returned.
 */
extern int path_remove(const char * filename);

/**
 * @brief Deletes all files in a given directory.
 * @param dirpath  path of the directory
 * @return Returns 0 for no any error, otherwise return a negative integer.
 */
extern int path_clear_dir(const char *dirpath);

/// @}

AMCC_DECL_END

#endif //#ifndef AMCC_STRING_H
